package admintools;
import msgs.*;

import java.net.*;
import java.io.*;
import java.util.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
/**
 * This will class will load an AdminTools GUI for controlling the chat
 * Team 9: Andrew Hayworth, Brian Parrella, Ryan Kortmann, Nina Papa
 * @author Brian Parrella
 *
 */
public class AdminTools implements TTConstants
{
	private String user, pass, ip;
	private final int pOut = 5555;
	private final int pIn = 5556;
	private final Vector<AdminMsg> outQ = new Vector<AdminMsg>();
	private final Vector<AdminMsg> inQ = new Vector<AdminMsg>();
	private boolean logged_in;
	private JFrame aLogin;
	private JFrame aGUI;
	private String myip;
	private byte[] aKey = null;
	private JList buddyList;
	private JList chatList;
	private JList bannedList;
	private JTextArea profile;
	
	public static void main(String args[])
	{
		String ip1 = "129.21.34.68";

		if (args.length >= 1)
		{
			ip1 = args[0];
		}

		AdminTools admin = new AdminTools(ip1);


	}

	public AdminTools(String _ip)
	{

		logged_in = false;
		ip = _ip;
		AdminLoginGUI alGUI = new AdminLoginGUI();
		alGUI.start();

		try
		{
			alGUI.join();
		}
		catch (InterruptedException ie)
		{
			System.out.println("Error logging in.");
			System.exit(1);
		}
		finally
		{
			postLogin();
		}


	}

	class AdminLoginGUI extends Thread
	{
		public void run()
		{
			aLogin = new JFrame();

			aLogin.setTitle("Admin Login");

			JLabel userLbl = new JLabel("Username: ");
			JLabel passLbl = new JLabel("Password: ");
			final JTextField userTxt = new JTextField(20);
			final JPasswordField passTxt = new JPasswordField(20);
			final JButton loginButton = new JButton("Login");

			JPanel jpTop = new JPanel(new FlowLayout());

			jpTop.add(userLbl);
			jpTop.add(userTxt);

			JPanel jpMid = new JPanel(new FlowLayout());

			jpMid.add(passLbl);
			jpMid.add(passTxt);

			JPanel jpLow = new JPanel(new FlowLayout());

			jpLow.add(loginButton);

			aLogin.add(jpTop, BorderLayout.NORTH);
			aLogin.add(jpMid, BorderLayout.CENTER);
			aLogin.add(jpLow, BorderLayout.SOUTH);

			aLogin.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			aLogin.pack();
			aLogin.setLocationRelativeTo(null);
			aLogin.setVisible(true);

			class LoginListener implements ActionListener
			{
				public void actionPerformed(ActionEvent e)
				{
					if (e.getSource() == loginButton)
					{
						if (userTxt.getText().length() >= 1 && passTxt.getPassword().length >= 1)
						{
							user = userTxt.getText();
							pass = charToString(passTxt.getPassword());
							logged_in = true;
						}
						else
							JOptionPane.showMessageDialog(null, "Please enter a user & pass.");
					}
				}

				public String charToString(char pw[])
				{
					String temp = "";

					for (int i = 0; i < pw.length; i++)
					{
						if (pw[i] != '\n')
							temp += pw[i];
					}

					return temp;
				}

			} //end LoginListener

			LoginListener LL = new LoginListener();
			loginButton.addActionListener(LL);

			while (!logged_in); //stays in thread until logged in

		} //end run

	} //end AdminLoginGUI class

	public void postLogin() //creates initial packet and starts listeners
	{

		AdminSender aSend = new AdminSender();
		aSend.start();

		AdminListener aListen = new AdminListener();
		aListen.start();

		AdminParser aParse = new AdminParser();
		aParse.start();

		AdminMsg amsg = new AdminMsg(ip, user, pass);
		amsg.setAction(AdminActions.LOGIN);
		amsg.setName(user);
		
		InetAddress inetAddr = null;
		try
		{
			inetAddr = InetAddress.getLocalHost();
		}
		catch (UnknownHostException uhe)
		{
			System.out.println("Problem getting local address.");
			System.exit(1);
		}
			
		myip = inetAddr.getHostAddress();
		System.out.println("Local IP address: " + ip);
		amsg.setIP(myip);
		outQ.add(amsg); //add intial login packet to outQ		

	}

	public void AdminGUI()
	{
		System.out.println("Login Success!");
		
		JPopupMenu userMenu = new JPopupMenu();
		JMenuItem getChats = new JMenuItem("Get User's Chats");
		JMenuItem getProfile = new JMenuItem("Get Profile");
		JMenuItem forceDC = new JMenuItem("Force Disconnect");
		JMenuItem banUser = new JMenuItem("Ban User");
		userMenu.add(getChats);
		userMenu.add(getProfile);
		userMenu.add(forceDC);
		userMenu.add(banUser);
		
		
		aGUI = new JFrame();
		JPanel jpTopLeft = new JPanel(new BorderLayout());
		JPanel jpTopRight = new JPanel(new BorderLayout());	
		JPanel jpTopMid = new JPanel();
		JPanel jpBottomLeft = new JPanel(new BorderLayout());
		JPanel jpBottomMid = new JPanel();
		JPanel jpBottomRight = new JPanel(new BorderLayout());
		JPanel jpBottom = new JPanel(new BorderLayout());
		
		buddyList = new JList();		
		chatList = new JList();
		bannedList = new JList();
		profile = new JTextArea(10,20);
		JLabel bListLabel = new JLabel("Users online: ");
		JLabel cListLabel = new JLabel("User chats: ");
		JLabel profileLabel = new JLabel("User profile: ");
		JLabel bannedUsers = new JLabel("Banned users: ");
		JButton unban = new JButton("Unban user");
		JButton setProfile = new JButton("Set Profile");
		JButton refreshOnline = new JButton("Refresh Lists");
		
		buddyList.setComponentPopupMenu(userMenu);
		
		getProfile.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent ae) 
			{
				getProfile((String) buddyList.getSelectedValue());
			}
		});
		
		getChats.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent ae) 
			{
				getUserChats((String) buddyList.getSelectedValue());
			}
		});
		
		refreshOnline.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent ae) 
			{
				buddyListRefresh();
			}
		});
		
		banUser.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent ae) 
			{
				banHammer((String) buddyList.getSelectedValue());
			}
		});
		
		
		setProfile.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent ae) 
			{
				setProfile(profile.getText(), (String) buddyList.getSelectedValue());
			}
		});
		
		unban.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent ae) 
			{
				if (!bannedList.isSelectionEmpty())
					unbanUser((String) bannedList.getSelectedValue());
			}
		});
		
		forceDC.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent ae) 
			{
				forceKick((String) buddyList.getSelectedValue());
			}
		});
		
		jpTopLeft.add(bListLabel, BorderLayout.NORTH);
		jpTopLeft.add(buddyList, BorderLayout.CENTER);
		jpTopLeft.add(refreshOnline, BorderLayout.SOUTH);
		
		jpTopRight.add(cListLabel, BorderLayout.NORTH);
		jpTopRight.add(chatList, BorderLayout.CENTER);
		
		jpBottomLeft.add(bannedUsers, BorderLayout.NORTH);
		jpBottomLeft.add(bannedList, BorderLayout.CENTER);
		jpBottomLeft.add(unban, BorderLayout.SOUTH);
		
		jpBottomRight.add(profileLabel, BorderLayout.NORTH);
		jpBottomRight.add(profile, BorderLayout.CENTER);
		jpBottomRight.add(setProfile, BorderLayout.SOUTH);
		
		jpBottom.add(jpBottomLeft, BorderLayout.WEST);
		jpBottom.add(jpBottomMid, BorderLayout.CENTER);
		jpBottom.add(jpBottomRight, BorderLayout.EAST);
		
		aGUI.add(jpTopLeft, BorderLayout.WEST);
		aGUI.add(jpTopMid, BorderLayout.CENTER);
		aGUI.add(jpTopRight, BorderLayout.EAST);
		aGUI.add(jpBottom, BorderLayout.SOUTH);

		buddyListRefresh();	//refreshes online users
		
		
		aGUI.setVisible(true);
		aGUI.setTitle("TigerTalk Admin");
		aGUI.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		aGUI.pack();
		aGUI.setLocationRelativeTo(null);
	}	

	
	public void buddyListRefresh() //refreshes online users
	{
		AdminRequestMsg armsg = new AdminRequestMsg(myip, user, null, aKey, null, null);
		armsg.setAction(AdminActions.LIST_USERS_ONLINE);
		outQ.add(armsg);
		
	}
	
	public void loadBannedUsers() //shows all banned users
	{
		AdminRequestMsg armsg = new AdminRequestMsg(myip, user, null, aKey, null, null);
		armsg.setAction(AdminActions.LIST_BANNED_USERS);
		outQ.add(armsg);
	}
	
	public void getProfile(String _user) //gets the selected user's profile
	{
		AdminRequestMsg armsg = new AdminRequestMsg(myip, user, null, aKey, _user, null);
		armsg.setName(user);
		armsg.setAction(AdminActions.GETPROFILE);
		armsg.setUser(_user);
		outQ.add(armsg);
	}
	
	public void getUserChats(String _user) //gets all current chats user is having
	{
			AdminRequestMsg armsg = new AdminRequestMsg(myip, user, null, aKey, _user, null);
			armsg.setName(user);
			armsg.setAction(AdminActions.LIST_USER_CHATS);
			armsg.setUser(_user);
			outQ.add(armsg);
	}
	
	public void forceKick(String _user) //force disconnects specified user
	{
		AdminRequestMsg armsg = new AdminRequestMsg(myip, user, null, aKey, _user, null);
		armsg.setAction(AdminActions.DISCONNECT_USER);
		armsg.setUser(_user);
		armsg.setName(user);
		outQ.add(armsg);
	}
	public void banHammer(String _user) //bans user from using chat services
	{
		BanMsg bmsg = new BanMsg(myip, user, null, aKey, _user);
		bmsg.setAction(AdminActions.BANHAMMER);
		outQ.add(bmsg);
	}
	
	public void unbanUser(String _user) //unbans users
	{
		BanMsg bmsg = new BanMsg(myip, user, null, aKey, _user);
		bmsg.setAction(AdminActions.UNBANHAMMER);
		outQ.add(bmsg);
		loadBannedUsers();
	}
	
	public void setProfile(String profile_text, String _user) //change users profiles
	{
		AdminRequestMsg armsg = new AdminRequestMsg(myip, user, null, aKey, _user, null);
		armsg.setUser(_user);
		armsg.setName(user);
		armsg.setAction(AdminActions.SETPROFILE);
		armsg.setO(profile_text);
		outQ.add(armsg);
	}
	
	class AdminSender extends Thread //sends anything added to outQ
	{

		private Socket sock;
		private AdminMsg amsg;
		private ObjectOutputStream oos;

		public void run()
		{
			while(true) //infinite loop
			{
				if (!outQ.isEmpty()) //if anything in Queue
				{
					amsg = (AdminMsg) outQ.remove(0);

					try
					{
						sock = new Socket(ip, pOut);
						oos = new ObjectOutputStream(sock.getOutputStream());

						oos.writeObject(amsg);
						oos.flush(); //send object to server

						oos.close();
						
						System.out.println("Action sent: " + amsg.getAction());
					}
					catch (UnknownHostException e)
					{
						e.printStackTrace();
					}
					catch (ConnectException ce)
					{
							System.err.println("Error connecting to " + ip + " on port " + pOut);
					}
					catch (IOException e)
					{
						e.printStackTrace();
					}
					
				}
				else 
				{
					try
					{
						Thread.sleep(100);
					}
					catch (InterruptedException ie)
					{
					}
				}
			}
		}
	}

	class AdminListener extends Thread //receives objects from server puts them in inQ
	{
		private Socket sock;
		private ServerSocket ssock;
		private AdminMsg amsg;
		private ObjectInputStream ois;

		public AdminListener()
		{
			try
			{
				ssock = new ServerSocket(pIn);
			}
			catch (IOException e)
			{
				System.err.println("Unable to open port " + pIn + " for listening.");
				e.printStackTrace();
			}
		}

		public void run()
		{
			while(true) //infinite loop
			{
				try
				{
					sock = ssock.accept();
					//System.out.println("Data received.");

					ois = new ObjectInputStream(sock.getInputStream());

					amsg = (AdminMsg) ois.readObject();

					System.out.println("Action received: " + amsg.getAction());
					inQ.add(amsg);

					ois.close();
				}
				catch (Exception e)
				{
					e.printStackTrace();
				}
			}
		}
	}

	class AdminParser extends Thread //waits for inQ to get an object then executes command
	{
		private AdminMsg amsg;

		public void run()
		{
			while(true) //infinite loop
			{
				if (!inQ.isEmpty())
				{
					amsg = inQ.remove(0);
					switch (amsg.getAction())
					{
						case LIST_USERS_ONLINE: //sets buddyList up with users logged online
							AdminRequestMsg armsg1 = (AdminRequestMsg) amsg;
							ArrayList<String> buddyArrayList = (ArrayList<String>) armsg1.getO();
							String[] bListStrArray = new String[buddyArrayList.size()];
							
							for (int i = 0; i < buddyArrayList.size(); i++)
								bListStrArray[i] = buddyArrayList.get(i);							
							
							if (buddyArrayList.size() > 0)
								buddyList.setListData(bListStrArray);
							else
							{
								String[] nousers = new String[1];
								nousers[0] = "No users online";
								buddyList.setListData(nousers);
							}
							loadBannedUsers();
							aGUI.pack();
							break;
						case LIST_USER_CHATS:
							AdminRequestMsg armsg2 = (AdminRequestMsg) amsg;
							
							String[] cListStrArray = (String[]) armsg2.getO();
								
							if (cListStrArray.length > 0)
								chatList.setListData(cListStrArray);
							else
							{
								String[] nochats = new String[1];
								nochats[0] = "User is not chatting.";
								chatList.setListData(nochats);
							}
							break;
						case GETPROFILE:
							AdminRequestMsg armsg3 = (AdminRequestMsg) amsg;
							String profile_text = (String) armsg3.getO();
							System.out.println(profile_text);
							profile.setText(profile_text);
							break;
						case LOGIN:
							
							if (amsg.getResponse() == Responses.OK)
							{
								aLogin.dispose();
								aKey = amsg.getAdminKey();
								AdminGUI();
							}
							else
							{
								System.out.println("Invalid login data. Exiting program.");
								JOptionPane.showMessageDialog(null, "Invalid user or pass.");
								System.exit(1);
							}
							break;
						case LIST_BANNED_USERS:
							AdminRequestMsg armsg4 = (AdminRequestMsg) amsg;
							ArrayList<String> banArrayList = (ArrayList<String>) armsg4.getO();
							String[] banListStrArray = new String[banArrayList.size()];
							
							for (int i = 0; i < banArrayList.size(); i++)
								banListStrArray[i] = banArrayList.get(i);							
							
							if (banArrayList.size() > 0)
								bannedList.setListData(banListStrArray);
							else
							{
								String[] nousersb = new String[1];
								nousersb[0] = "No users banned";
								bannedList.setListData(nousersb);
							}
							
							aGUI.pack();
							break;
						case DISCONNECT_USER:
							if (amsg.getResponse() == Responses.OK)
							{
								buddyListRefresh();
							}
							else
								System.out.println("ERROR");
							break;
						default:
					}
				}
				else 
				{
					try
					{
						Thread.sleep(100);
					}
					catch (InterruptedException ie)
					{
					}
				}
			}
		}
	}
}